package DSPackage;

import jade.core.*;
import jade.core.behaviours.*;

import jade.lang.acl.*;

import jade.content.*;
import jade.content.onto.basic.*;
import jade.content.lang.sl.*;

import jade.util.leap.Iterator;

import jade.domain.*;
import jade.domain.mobility.*;
import jade.domain.JADEAgentManagement.*;
import jade.domain.FIPAAgentManagement.*;

import jade.wrapper.*;

import java.util.*;

/***
 * ControlAgent
 */
public class ControlAgent extends Agent {
    // AMS fetched variables
    private AMSAgentDescription[] agents = null;
    private AID[] agentID = null;
    private Iterator it;
    private Map locations = new HashMap();

    // Different variables specific to the Control agent
    private DS ds;
    private String appName;
    private String maxBW;
    private Random r;

    // Used to create container and agent
    private ContainerController cc;
    private AgentController ac = null;
    private String name;
    private int dsacnt;

    transient protected ControlAgent dsa;

    @Override
    protected void setup() {
        init();
        r = new Random();
        dsacnt = r.nextInt();

        Object[] args = getArguments();
        this.ds = (DS) args[0];
        this.appName = (String) args[1];
        this.cc = (ContainerController) args[2];

        Action action = new Action(getAMS(), new QueryPlatformLocationsAction());

        // Creating request to AMS service for available containers
        ACLMessage request = new ACLMessage(ACLMessage.REQUEST);
        request.setLanguage(new SLCodec().getName());
        request.setOntology(MobilityOntology.getInstance().getName());

        try {
            // Sending message
	    getContentManager().fillContent(request, action);
	    request.addReceiver(action.getActor());
	    send(request);
	}
	catch (Exception e) {
            System.err.println("Error sending message to AMS service.");
        }

        // Receive response from AMS. Message template making sure to not
        // continue until the right response is received.
        MessageTemplate mt = MessageTemplate.and(
                MessageTemplate.MatchSender(getAMS()),
                MessageTemplate.MatchPerformative(ACLMessage.INFORM));

        ACLMessage resp = blockingReceive(mt);

        try {
            // Handling respone from AMS service
            ContentElement ce = getContentManager().extractContent(resp);
            Result result = (Result) ce;
            it = result.getItems().iterator();
        }
        catch (Exception e) {
            System.err.println("Error in handling respone from AMS service");
        }

        // Search the AMS for agents to access
        try {
            SearchConstraints c = new SearchConstraints();
            c.setMaxResults(new Long(-1));
            agents = AMSService.search(this, new AMSAgentDescription (), c );
        }
        catch (Exception e) {
            System.err.println("Problems finding all known agents in AMS.");
        }

        agentID = new AID[agents.length];
        // Extract agent ID
        for (int i=0 ; i < agents.length ;i++)
        {
            agentID[i] = agents[i].getName();
        }

        // Program the main behaviour of this agent
        addBehaviour(new InitMoveAgent(this)); 
    }

    private void init() {
        // Register SLCodec and MobilityOntology in content manager
        getContentManager().registerLanguage(new SLCodec());
        getContentManager().registerOntology(MobilityOntology.getInstance());
    }

/*
* Receive all commands from the controller agent
*/
class InitMoveAgent extends SimpleBehaviour {

    private boolean finished = false;
    private boolean firstrun = true;

    public InitMoveAgent(Agent a) {
        super(a);

    }

    public void action() {
        if (firstrun) {
            int i = 0;
            while (it.hasNext()) {
                Location loc = (Location)it.next();
                locations.put(i, loc);
                i++;
            }
            name = "DSA"+dsacnt;

            Object[] argument = new Object[6];
            argument[0] = locations;
            argument[1] = appName;
            argument[2] = getAID();
            argument[3] = agentID;
            try {
                argument[4] = cc.getContainerName();
            }
            catch (Exception e) { }
            argument[5] = name;

            try {
                ac = cc.createNewAgent(name, DSAgent.class.getName(), argument);
                ac.start();
            } catch (Exception e) {
                System.err.println("Problem creating new agent");
            }

            firstrun = false;
        }

        MessageTemplate mt = MessageTemplate.and(
                MessageTemplate.MatchConversationId(name),
                MessageTemplate.MatchPerformative(ACLMessage.INFORM));
        ACLMessage reply = receive(mt);

        if(ds != null && reply != null) {
            maxBW = reply.getContent();
            ds.restart(maxBW);
            finished = true;
        }
        else {
            block();
        }


    }

    @Override
    public boolean done() {
        return finished;
    }
    }
}